﻿// (c) Norbert Huffschmid
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.

using System;
using System.Security.Principal;
using log4net;
using NAudio.Wave;
using NProtocol.Codec;
using ShoutBox.Core;

namespace ShoutBox
{
    /// <summary>
    /// Windows-based platform adapter for microphone recording
    /// </summary>
    public class WindowsWaveInPlatformAdapter : IPlatformAdapterAudioIn
    {
        /// <summary>
        /// Fires when audio data is available
        /// </summary>
        public event EventHandler<RealTimeDataEventArgs> AudioDataAvailable;


        /// <summary>
        /// Gets the shoutbox name
        /// </summary>
        public string ShoutBoxName
        {
            get { return WindowsIdentity.GetCurrent().Name; }
        }


        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private IWaveIn waveIn;
        private bool disposed = false;


        /// <summary>
        /// Constructor
        /// </summary>
        public WindowsWaveInPlatformAdapter()
        {
            log.Debug("Constructor");

            // init wave in
            this.waveIn = new WaveInEvent();
            this.waveIn.WaveFormat = new WaveFormat(8000, 16, 1);
            this.waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);

            // workaround delay at first recording
            // This workaround has a drawback on bluetooth A2DP audio headsets:
            // When the microphone is used some devices fall back to another (very bad-quality) profile
            // ==> ShoutBox running hidden in systray causes bad-quality audio output on bluetooth headset!
            // ==> USE MICROPHONE ONLY WHEN NEEDED!
            //this.waveIn.StartRecording();
            //this.waveIn.StopRecording();
        }


        /// <summary>
        /// Start recording
        /// </summary>
        public void StartRecording()
        {
            log.Debug("StartRecording");

            this.waveIn.StartRecording();
        }

        /// <summary>
        /// StopRecording
        /// </summary>
        public void StopRecording()
        {
            log.Debug("StopRecording");

            this.waveIn.StopRecording();
        }

        
        /// <summary>
        /// Release all resources
        /// </summary>
        public void Dispose()
        {
            log.Debug("Dispose");

            Dispose(true);
            GC.SuppressFinalize(this);
        }


        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    this.waveIn.Dispose();
                }
            }
            disposed = true;
        }


        private void waveIn_DataAvailable(object sender, WaveInEventArgs e)
        {
            log.Debug("waveIn_DataAvailable: " + e.BytesRecorded.ToString() + " bytes");

            if (e.BytesRecorded > 0)
            {
                byte[] recordedData = new byte[e.BytesRecorded];
                Buffer.BlockCopy(e.Buffer, 0, recordedData, 0, e.BytesRecorded);

                if (this.AudioDataAvailable != null)
                {
                    this.AudioDataAvailable(this, new RealTimeDataEventArgs( 
                        recordedData, NProtocol.Codec.RealTimeDataFormat.Audio_8kHz_16Bit_Mono, null));
                }
            }
        }
    }
}
